%{
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 * Copyright (c) 1999 by Sun Microsystems, Inc.
 * All rights reserved.
 */

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libintl.h>
#include <string.h>

#include <regexpr.h>

#include "iconv_tm.h"
#include "itmcomp.h"
#include "y.tab.h"

static itm_data_t	*hexadecimal_data(int, char *);
static itm_data_t	*name_data(int, char *);
static void		filename_lineno(void);
static int		at_name_to_token(char *);


%}

%start	norm comment

DECIMAL		([0-9]+)
OCTAL		(0[0-7][0-7]+)
HEXADECIMAL	(("0x"|"0X")([0-9A-Fa-f])+)
ITMNAME		(([^% \t\n\r])+"%"([^% \t\n\r])+)
ATNAME		"@"([0-9A-Za-z_]+)
NAME		([A-Za-z_][A-Za-z0-9_]*)
MAPTYPE_NAME	(automatic|dense|index|hash|binary)

%%

[ \t\n]+	;
"//".*"\n"	;

^"#"[ \t]*{DECIMAL}[ \t]*"\"".*"\"".*"\n" {
			filename_lineno();
		}

^"#".*"\n"	{
			if (NULL == cmd_opt.preprocess) {
				itm_error(
				gettext("warning: "
					"preprocess may be required\n"));
			}
		}

{DECIMAL}	{
			yylval.num = strtoul(yytext, (char **)NULL, 10);
			return (DECIMAL);
		}

{OCTAL}		{	yylval.num = strtoul(yytext, (char **)NULL, 8);
			return (DECIMAL);
		}

{HEXADECIMAL}	{	yylval.data = hexadecimal_data(yyleng - 2, yytext + 2);
			return (HEXADECIMAL);
		}

{ITMNAME}	{	yylval.data = str_to_data(yyleng, yytext);
			return (ITMNAME);
		}

{ATNAME}	{	return at_name_to_token(yytext);
		}

{MAPTYPE_NAME}	{	yylval.num = at_name_to_token(yytext);
			yylval.data = name_data(yyleng, yytext);
			return (MAPTYPE_NAME);

		}

{NAME}		{	yylval.num = at_name_to_token(yytext);
			if (0 != yylval.num) {
				return (yylval.num);
			} else {
				yylval.data = name_data(yyleng, yytext);
				return (NAME);
			}
		}


"{"		{return (CBO);}
"}"		{return (CBC);}
"["		{return (SBO);}
"]"		{return (SBC);}
"("		{return (PO);}
")"		{return (PC);}
";"		{return (SC);}
","		{return (COMMA);}
":"		{return (COLON);}
"..."		{return (ELLIPSES);}


"="		{return (ASSIGN);}
"||"		{return (LOR);}
"&&"		{return (LAND);}
"|"		{return (OR);}
"^"		{return (XOR);}
"&"		{return (AND);}
"=="		{return (EQ);}
"!="		{return (NE);}
"<"		{return (LT);}
"<="		{return (LE);}
">"		{return (GT);}
">="		{return (GE);}
"<<"		{return (SHL);}
">>"		{return (SHR);}
"+"		{return (PLUS);}
"-"		{return (MINUS);}
"*"		{return (MUL);}
"/"		{return (DIV);}
"%"		{return (MOD);}
"!"		{return (NOT);}
"~"		{return (NEG);}

.		{	itm_error(
				gettext("Unrecognized token '%1$c' \n"),
				cmd_opt.my_name, yytext[0]);
			return (0);
		}

%%

/*
 * lexinit - starts the Lexical Analyzer off in the right start condition
 */
void
lexinit()
{
	BEGIN norm;
}

/* does this really need to be here? */
int
yywrap()
{
	return (1);
}

void
yyerror(char *s)
{
	extern int	yylineno;

	itm_error(
		gettext("%1$s: file(%2$s) line(%3$d) last token(%4$s)\n"),
		s, itm_input_file, yylineno, yytext);

	exit(ITMC_STATUS_BT);
}

typedef struct {
	char	*name;
	int	token;
} at_name_token_t;

/*
 * NOT: This table must be sorted alphabetically.
 */
static at_name_token_t at_table[] = {
	"@automatic",	MAPTYPE_AUTO,
	"@binary",	MAPTYPE_BINARY,
	"@between",	BETWEEN,
	"@condition",	CONDITION,
	"@default",	ITM_DEFAULT,
	"@dense",	MAPTYPE_DENSE,
	"@direction",	DIRECTION,
	"@discard",	DISCARD,
	"@else",	ITM_ELSE,
	"@error",	ERROR,
	"@escapeseq",	ESCAPESEQ,
	"@false",	ITM_FALSE,
	"@hash",	MAPTYPE_HASH,
	"@identical",	ITM_IDENTICAL,
	"@if",		ITM_IF,
	"@in",		ITM_IN,
	"@index",	MAPTYPE_INDEX,
	"@init",	ITM_INIT,
	"@input",	ITM_IN,
	"@inputsize",	ITM_INSIZE,
	"@map",		MAP,
	"@maptype",	MAPTYPE,
	"@no_change_copy",	ITM_IDENTICAL,
	"@nop",		NOP,
	"@operation",	OPERATION,
	"@out",		ITM_OUT,
	"@output",	ITM_OUT,
	"@output_byte_length",	RESULTLEN,
	"@outputsize",	ITM_OUTSIZE,
	"@printchr",	PRINTCHR,
	"@printhd",	PRINTHD,
	"@printint",	PRINTINT,
	"@reset",	RESET,
	"@resultlen",	RESULTLEN,
	"@return",	RETURN,
	"@true",	ITM_TRUE,
	"automatic",	MAPTYPE_AUTO,
	"between",	BETWEEN,
	"binary",	MAPTYPE_BINARY,
	"break",	BREAK,
	"condition",	CONDITION,
	"default",	ITM_DEFAULT,
	"dense",	MAPTYPE_DENSE,
	"direction",	DIRECTION,
	"discard",	DISCARD,
	"else",		ITM_ELSE,
	"error",	ERROR,
	"escapeseq",	ESCAPESEQ,
	"false",	ITM_FALSE,
	"hash",		MAPTYPE_HASH,
	"if",		ITM_IF,
	"index",	MAPTYPE_INDEX,
	"init",		ITM_INIT,
	"input",	ITM_IN,
	"inputsize",	ITM_INSIZE,
	"map",		MAP,
	"maptype",	MAPTYPE,
	"no_change_copy",	ITM_IDENTICAL,
	"nop",		NOP,
	"operation",	OPERATION,
	"output",	ITM_OUT,
	"output_byte_length",	RESULTLEN,
	"outputsize",	ITM_OUTSIZE,
	"printchr",	PRINTCHR,
	"printhd",	PRINTHD,
	"printint",	PRINTINT,
	"reset",	RESET,
	"return",	RETURN,
	"true",		ITM_TRUE,
};

int
at_name_to_token(char *s)
{
	int	high;
	int	mid;
	int	low;
	int	result;

	TRACE_MESSAGE('l', ("at_name_to_token: %s", s));
	for (low = 0, high = (sizeof (at_table) /
				sizeof (at_name_token_t));
	    low < high; /* NOP */) {
		mid = (low + high) / 2;
		result = strcmp(s, at_table[mid].name);
		if (result < 0) {
			high = mid;
		} else if (0 < result) {
			low = mid + 1;
		} else { /* 0 == result */
			TRACE_MESSAGE('l', (" %d\n", at_table[mid].token));
			return (at_table[mid].token);
		}
	}
	TRACE_MESSAGE('l', (" - not found\n"));
	return (0);
}

static itm_data_t *
hexadecimal_data(int seqsize, char *seq)
{
	itm_data_t	*data;
	char		*binary;
	int		i, j;
	int		val;
	int		high;
	int		low;
	int		size;

	/* size is assured to be multiple of 2 */
	assert(seqsize != 0);
	size = seqsize + 1;
	size /= 2;
	if (size > MAXSEQUENCE) {
		itm_error(
		gettext(" specified sequence must be less than %$1d\n"),
		MAXSEQUENCE);
		return (NULL);
	}
	binary = malloc_vital(size);
	i = j = 0;
	if (seqsize % 2 != 0) {
		low =  *(seq);
		if (('0' <= low) && (low <= '9')) {
			val = (low - '0');
		} else if (('a' <= low) && (low <= 'f')) {
			val = (low - 'a' + 10);
		} else if (('A' <= low) && (low <= 'F')) {
			val = (low - 'A' + 10);
		}
		*(binary + i) = val;
		i++;
		j++;
	}
	for (/* NOP */; i < size; i++, j += 2) {
		high = *(seq + j);
		low =  *(seq + j + 1);
		if (('0' <= high) && (high <= '9')) {
			val = ((high - '0') << 4);
		} else if (('a' <= high) && (high <= 'f')) {
			val = ((high - 'a' + 10) << 4);
		} else if (('A' <= high) && (high <= 'F')) {
			val = ((high - 'A' + 10) << 4);
		}
		if (('0' <= low) && (low <= '9')) {
			val |= (low - '0');
		} else if (('a' <= low) && (low <= 'f')) {
			val |= (low - 'a' + 10);
		} else if (('A' <= low) && (low <= 'F')) {
			val |= (low - 'A' + 10);
		}
		*(binary + i) = val;
	}

	data = malloc_vital(sizeof (itm_data_t));

	data->size = size;
	if (size <= sizeof (data->place)) {
		(void) memmove(&(data->place), binary, size);
		free(binary);
	} else {
		data->place.itm_ptr = (itm_place2_t)binary;
	}

	return (data);
}

static itm_data_t *
name_data(int size, char *seq)
{
	itm_data_t *data;


	if (size > MAXNAMELENGTH) {
		itm_error(gettext("the length(%d) exceed limitation(%d)"),
		size, MAXNAMELENGTH);
		exit(ITMC_STATUS_BT2);
	}
	data = malloc_vital(sizeof (itm_data_t));

	data->size = size;
	if (size <= sizeof (data->place)) {
		(void) memmove(&(data->place), seq, size);
	} else {
		data->place.itm_ptr = (itm_place2_t)malloc_vital(size);
		(void) memmove((char *)(data->place.itm_ptr), seq, size);
	}

	return (data);
}

static void
filename_lineno(void)
{
	static char	*re;
	static char	restr[] =
			"^#[ \t]*\\([0-9]\\{1,\\}\\)[ \t]*\"\\(.*\\)\".*";
	int		match;
	extern char	*braslist[];
	extern char	*braelist[];
	static char	*filename;
	int		len;
	int		lineno;

	if (NULL == re) {
		re = compile(restr, NULL, NULL);
		if (NULL == re) {
			itm_error(
				gettext("REGEXP compile error\n"));
			exit(ITMC_STATUS_BT);
		}
	}
	match = step(yytext, re);
	if (0 != match) {
		lineno = atoi(braslist[0]);
		free(filename);
		len = braelist[1] - braslist[1];
		filename = malloc_vital(len + 1);
		(void) memcpy(filename, braslist[1], len);
		*(filename + len) = '\0';
		itm_input_file = filename;
		yylineno = lineno;
	}
}
